/*
 * Copyright (c) 2010, Nikolaus Moll
 * All rights reserved.
 */
package net.miblounge.gradecalculator.core;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.xml.bind.annotation.XmlTransient;

import net.miblounge.gradecalculator.core.student.ExaminationResult;
import net.miblounge.gradecalculator.core.student.ExaminationResultType;
import net.miblounge.gradecalculator.core.student.Student;
import net.miblounge.gradecalculator.core.student.StudentModule;
import net.miblounge.gradecalculator.grade.IGradeFactory;
import net.miblounge.gradecalculator.grade.IOverallGrade;

public class AdaptedRegulations {
	
	private class Result {
		private IOverallGrade grade;
		private float ects;
	}
	
	private List<StudentModule> modules;
	private Student student;
	
	private final Result[] results;
	
	private volatile int spoECTS = 0;
	private List<ExaminationResult> unassignedResults;
	private final IGradeFactory fab;
	
	public AdaptedRegulations(final Student student)
	{
		this.student = student;
   		fab = GradeFactoryUtil.getInstance().getFab(student.getUniversity().getCountryCode());
		modules = new ArrayList<StudentModule>();
		unassignedResults = new ArrayList<ExaminationResult>();
		
		results = new Result[ExaminationResultType.values().length];
		for (int i = 0; i < results.length; i++) {
			results[i] = new Result();
		}
	}
	
	public Student getStudent()
	{
		return student;
	}
	
	public void addModule(final StudentModule module)
	{
		modules.add(module);
	}
	
	public List<StudentModule> getModules()
	{
		// make working copy
		final ArrayList<StudentModule> result = new ArrayList<StudentModule>(modules);
		Collections.sort(result);
		return result;
	}

	public String getName() {
		return "student's spo";
	}
	
	private void update()
	{
		for (ExaminationResultType r : ExaminationResultType.values()) {
			results[r.ordinal()].ects = 0;
			results[r.ordinal()].grade = fab.createOverallGrade();
		}

		if (student.getUniversity() == null) {
			// nothing to do
			return;
		}
		
		for (StudentModule m : modules) {
			
			for (ExaminationResultType r : ExaminationResultType.values()) {
				final float ects = m.getECTS(r);

				if (m.isGraded(r)) {
					results[r.ordinal()].grade.add(m.getGrade(r), ects);
				}
				
				results[r.ordinal()].ects += ects;
			}
		}
	}
	
	public float getECTS(final ExaminationResultType passed)
	{
		update();
		return results[passed.ordinal()].ects;
	}
		
	
	public String getGrade(final ExaminationResultType passed)
	{
		update();
		
		final IOverallGrade grade = results[passed.ordinal()].grade; 
		
		if (grade == null) {
			return "";
		}

		return grade.getGrade();
	}

	public int getSPOECTS()
	{
		int result = spoECTS;
		if (result == 0) {
			for (StudentModule m : modules) {
				result += m.getModule().getECTS();
			}

			spoECTS = result;
		}
		return result;
	}

	public List<ExaminationResult> getUnassignedResults() {
		return unassignedResults;
	}

	public void setUnassignedResults(final List<ExaminationResult> results) {
		unassignedResults = new ArrayList<ExaminationResult>(results);
	}

	
	/**
	 * Removes the result from list of unassigned results. Does not remove the
	 * result from the student.
	 * @param result
	 */
	public void removeUnassignedResult(final ExaminationResult result)
	{
		unassignedResults.remove(result);
	}
	
	@XmlTransient
	public ExaminationResult getUnassignedResult(final String courseName) {
		for (ExaminationResult result : unassignedResults) 
		{
			if (result.getCourseIdentifier().equals(courseName)) {
				return result;
			}
		}
		return null;
	}

	
	public IGradeFactory getGradeFactory() {
		return fab;
	}
	
}
